package com.zx.idc.backend.gui.ins.service;

import com.rxliuli.rxeasyexcel.domain.ExcelImportError;
import com.rxliuli.rxeasyexcel.domain.ImportDomain;
import com.zx.idc.backend.gui.scheduler.ins.filtermonitorlog.service.MonitorInstructionJobService;
import com.zx.idc.common.constants.InsCacheStatus;
import com.zx.idc.common.exception.EncryptException;
import com.zx.idc.common.exception.ExcelImportErrorException;
import com.zx.idc.common.exception.GlobalException;
import com.zx.idc.common.exception.InstructionUpdateTimeOutException;
import com.zx.idc.ds.base.house.service.IBaseHouseInfoService;
import com.zx.idc.ds.ins.entity.InsMonitorArchive;
import com.zx.idc.ds.ins.service.IInsMonitorArchiveService;
import com.zx.idc.ds.ins.service.IInsMonitorRuleService;
import com.zx.idc.ds.ins.service.IInsMonitorService;
import com.zx.idc.ds.ins.vo.InsFilterVo;
import com.zx.idc.ds.ins.vo.InsMonitorVo;
import com.zx.idc.ds.sys.service.ISysGlobalStatusService;
import com.zx.idc.internal.exception.SendMessageException;
import com.zx.idc.internal.ins.InstructionCallResult;
import com.zx.idc.internal.service.SMMSMonitorInstructionService;
import com.zx.idc.qc.exception.JobExistsException;
import com.zx.idc.qc.exception.QuartzJobException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
public class InsMonitorInterfaceService {
    private static final Logger LOG = LoggerFactory.getLogger(InsFilterInterfaceService.class);
    private static final String ADD_TYPE = "0";
    private static final Integer SUCCESS = 200;

    @Autowired
    private IInsMonitorService iInsMonitorService;
    @Autowired
    private IInsMonitorArchiveService insMonitorArchiveService;

    @Autowired
    private IBaseHouseInfoService iBaseHouseInfoService;

    @Autowired
    private MonitorInstructionJobService monitorInstructionJobService;

    @Autowired
    private SMMSMonitorInstructionService smmsMonitorInstructionService;

    @Autowired
    private ISysGlobalStatusService iSysGlobalStatusService;

    @Autowired
    private IInsMonitorRuleService iInsMonitorRuleService;

    public Boolean add(InsMonitorVo insMonitorVo) throws EncryptException, JobExistsException, QuartzJobException, SendMessageException {
        if (Duration.between(insMonitorVo.getExpiredTime(), LocalDateTime.now()).getSeconds() > 0) {
            throw new GlobalException("过期时间已过，无法添加监测指令");
        }
        Boolean flag = iInsMonitorService.add(insMonitorVo);

        if (!flag)
            return false;

        //插入一个副本到存档表
        InsMonitorArchive insMonitorArchive = new InsMonitorArchive();
        BeanUtils.copyProperties(insMonitorVo, insMonitorArchive);
        insMonitorArchiveService.insert(insMonitorArchive);

        //生效时间小于当前时间
        if (Duration.between(insMonitorVo.getEffectTime(), LocalDateTime.now()).getSeconds() > 0) {
            //直接调用
            for (String houseId : insMonitorVo.getHouseId().split(",")) {
                InstructionCallResult result = smmsMonitorInstructionService.addRules(insMonitorVo, houseId);
                if (result == null || result.getCode() != 200) {
                    LOG.warn("send addition monitor instruction to filter server fail, command id: {}", insMonitorVo.getId());
                }
            }
            LOG.info("添加监测规则成功，命令id：{}", insMonitorVo.getId());
            //添加删除规则定时任务
            monitorInstructionJobService.generateDeleteScheduler(insMonitorVo.getId());
            cleanInsCache(insMonitorVo);
            return true;
        }
        monitorInstructionJobService.generateScheduler(insMonitorVo.getId());
        //批量修改指令添加清除缓存状态
        cleanInsCache(insMonitorVo);
        return true;
    }

    public Boolean updateInsMonitor(InsMonitorVo insMonitorVo) throws EncryptException, JobExistsException, QuartzJobException, SendMessageException {
        if (Duration.between(insMonitorVo.getEffectTime(), LocalDateTime.now()).getSeconds() >= 0) {
            throw new InstructionUpdateTimeOutException("生效时间已过,不能修改");
        }
        if (Duration.between(insMonitorVo.getExpiredTime(), LocalDateTime.now()).getSeconds() > 0) {
            throw new GlobalException("过期时间已过，监测指令已作废");
        }
        InsMonitorVo insMonitorOld = iInsMonitorService.updateInsMonitor(insMonitorVo);
        if (insMonitorOld == null)
            return false;

        //更新副本到存档表
        InsMonitorArchive insMonitorArchive = new InsMonitorArchive();
        BeanUtils.copyProperties(insMonitorVo, insMonitorArchive);
        insMonitorArchiveService.updateById(insMonitorArchive);

        //删除定时任务
        monitorInstructionJobService.deleteScheduler(insMonitorOld.getId());
        //添加定时任务指令
        monitorInstructionJobService.generateScheduler(insMonitorOld.getId());
        cleanInsCache(insMonitorVo);
        return true;
    }

    private void cleanInsCache(InsMonitorVo insMonitorVo) {
        List<Long> ids = Arrays.stream(insMonitorVo.getHouseId().split(","))
            .map(Long::valueOf)
            .collect(Collectors.toList());
        iSysGlobalStatusService.updateInsStatusByHouseIds(ids, InsCacheStatus.ClEAN_CACHE_NEED);
    }

    public ImportDomain<InsMonitorVo> importData(List<InsMonitorVo> data, Map<String, Integer> columnInfoMap) throws EncryptException, JobExistsException, QuartzJobException, SendMessageException {
        ImportDomain<InsMonitorVo> insMonitorVoImportDomain;
        try {
            insMonitorVoImportDomain = iInsMonitorService.insertImportData(data, columnInfoMap);
        } catch (ExcelImportErrorException e) {
            throw e;
        }
        List<ExcelImportError> errors = insMonitorVoImportDomain.getErrors();
        //有错误数据直接返回
        if (errors != null && !errors.isEmpty()) {
            return insMonitorVoImportDomain;
        }
        //添加任务 调用拦截器接口
        List<InsMonitorVo> importData = insMonitorVoImportDomain.getData();
        if (importData != null && !importData.isEmpty()) {
            for (InsMonitorVo datum : importData) {
                monitorInstructionJobService.generateScheduler(datum.getId());
            }
        }
        List<Long> ids = iBaseHouseInfoService.selectListReturnId();
        iSysGlobalStatusService.updateInsStatusByHouseIds(ids, InsCacheStatus.ClEAN_CACHE_NEED);
        return insMonitorVoImportDomain;
    }

    public void deleteInsMonitor(InsMonitorVo insMonitorVo) throws EncryptException, SendMessageException, JobExistsException, QuartzJobException {
        monitorInstructionJobService.deleteScheduler(insMonitorVo.getId());
        iInsMonitorService.deleteById(insMonitorVo.getId());
        Map<String, Object> columnMap = new HashMap<>();
        columnMap.put("insId", insMonitorVo.getId());
        iInsMonitorRuleService.deleteByMap(columnMap);
        for (String houseId : insMonitorVo.getHouseId().split(",")) {
            //调用删除服务接口
            InstructionCallResult result = smmsMonitorInstructionService.delRules(insMonitorVo, houseId);
            if (!SUCCESS.equals(result.getCode())) {
                LOG.warn("send deletion monitor instruction to filter server fail. command id: {}, receive response code: {}, receive response message: {}, houseId: {}",
                    insMonitorVo.getId(), result.getCode(), result.getComments(), houseId);
            }
        }
    }
}
